package ec.linde.modulos.dao;

import java.util.List;
import java.util.Map;

import javax.ejb.Stateless;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Fetch;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import ec.linde.persistencia.entidades.ProdConceptosMateriales;
import ec.linde.persistencia.entidades.proyectos.CronogramaRdo;
import ec.linde.persistencia.entidades.proyectos.DetalleRdo;
import ec.linde.persistencia.entidades.proyectos.Rdo;

/**
 * TODO: Agregar descripcion
 * 
 * @FechaCreacion: 29/09/2014
 * @author: Alex Carrillo
 * @FechaModificacion: 29/09/2014
 * @author: Alex Carrillo
 * @version: 1.0
 */
@Stateless
public class RdoDao extends AbstractDao<Rdo> {
	/**
	 * Constructor por defecto que inicializa el AbstractDao con la clase ProdRdo
	 */
	public RdoDao() {
		super(Rdo.class);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.asinfo.as2.dao.AbstractDaoAS2#obtenerListaPorPagina(int, int, java.lang.String, boolean, java.util.Map)
	 */
	public List<Rdo> obtenerListaPorPagina(int startIndex, int pageSize, String sortField, boolean sortOrder, Map<String, String> filters) {
		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
		CriteriaQuery<Rdo> criteriaQuery = criteriaBuilder.createQuery(Rdo.class);
		Root<Rdo> from = criteriaQuery.from(Rdo.class);
		from.fetch("planOperativo", JoinType.LEFT).fetch("proyecto", JoinType.LEFT);
		
		final List<Expression<?>> expresiones = obtenerExpresiones(filters, criteriaBuilder, from);
		criteriaQuery.where(expresiones.toArray(new Predicate[expresiones.size()]));

		agregarOrdenamiento(sortField, sortOrder, criteriaBuilder, criteriaQuery, from);

		CriteriaQuery<Rdo> select = criteriaQuery.select(from);
		TypedQuery<Rdo> typedQuery = em.createQuery(select);
		agregarPaginacion(startIndex, pageSize, typedQuery);

		return typedQuery.getResultList();
	}

	/**
	 * 
	 * Retorna un lista para ser mostrado en un combo
	 * 
	 * @param sortField
	 * @param sortOrder
	 * @param filters
	 * @return
	 */
	public List<Rdo> obtenerListaCombo(String sortField, boolean sortOrder, Map<String, String> filters) {

		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
		CriteriaQuery<Rdo> criteriaQuery = criteriaBuilder.createQuery(Rdo.class);
		Root<Rdo> from = criteriaQuery.from(Rdo.class);
		from.fetch("planOperativo", JoinType.LEFT);

		agregarOrdenamiento(sortField, sortOrder, criteriaBuilder, criteriaQuery, from);

		List<Expression<?>> empresiones = obtenerExpresiones(filters, criteriaBuilder, from);
		criteriaQuery.where(empresiones.toArray(new Predicate[empresiones.size()]));

		CriteriaQuery<Rdo> select = criteriaQuery.select(from);
		TypedQuery<Rdo> typedQuery = em.createQuery(select);

		return typedQuery.getResultList();
	}

	/**
	 * Carga ProdRdo
	 * 
	 * @param idRdo
	 * @return ProdRdo
	 */
	public Rdo cargarDetalle(int idRdo) {

		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

		CriteriaQuery<Rdo> cqCabecera = criteriaBuilder.createQuery(Rdo.class);
		Root<Rdo> fromCabecera = cqCabecera.from(Rdo.class);
		Fetch<Object, Object> planOperativo = fromCabecera.fetch("planOperativo", JoinType.LEFT);
		Fetch<Object, Object> proyecto = planOperativo.fetch("proyecto", JoinType.LEFT);

		proyecto.fetch("usuario", JoinType.LEFT);
		proyecto.fetch("persona", JoinType.LEFT);
		proyecto.fetch("cliente", JoinType.LEFT);
		proyecto.fetch("sucursal", JoinType.LEFT);
		proyecto.fetch("contactoCliente", JoinType.LEFT);
		proyecto.fetch("contratista", JoinType.LEFT);
		proyecto.fetch("contactoContratista", JoinType.LEFT);

		Path<Integer> pathId = fromCabecera.get("idRdo");
		cqCabecera.where(criteriaBuilder.equal(pathId, idRdo));
		CriteriaQuery<Rdo> selectRdo = cqCabecera.select(fromCabecera);
		Rdo rdo = em.createQuery(selectRdo).getSingleResult();

		// Carga el detalle de las proformas Secundarias
		CriteriaQuery<DetalleRdo> cqDetalleRdo = criteriaBuilder.createQuery(DetalleRdo.class);
		Root<DetalleRdo> fromDetalleRdo = cqDetalleRdo.from(DetalleRdo.class);
		fromDetalleRdo.fetch("partida", JoinType.LEFT);
		fromDetalleRdo.fetch("concepto", JoinType.LEFT);
		cqDetalleRdo.where(criteriaBuilder.equal(fromDetalleRdo.join("rdo"), rdo));
		CriteriaQuery<DetalleRdo> selectDetalleRdo = cqDetalleRdo.select(fromDetalleRdo);

		List<DetalleRdo> listaDetalleRdo = em.createQuery(selectDetalleRdo).getResultList();
		rdo.setListaDetalleRdo(listaDetalleRdo);

		// Carga el cronograma
		for (DetalleRdo detalleRdo : listaDetalleRdo) {

			em.detach(detalleRdo);
			detalleRdo.setRdo(rdo);

			CriteriaQuery<CronogramaRdo> cqCronograma = criteriaBuilder.createQuery(CronogramaRdo.class);
			Root<CronogramaRdo> fromCronograma = cqCronograma.from(CronogramaRdo.class);
			cqCronograma.where(criteriaBuilder.equal(fromCronograma.join("detalleRdo"), detalleRdo));
			CriteriaQuery<CronogramaRdo> selectCronograma = cqCronograma.select(fromCronograma);
			List<CronogramaRdo> listaCronogramaRdo = em.createQuery(selectCronograma).getResultList();
			detalleRdo.setListaCronogramaRdo(listaCronogramaRdo);

			for (CronogramaRdo cronogramaRdo : listaCronogramaRdo) {
				em.detach(cronogramaRdo);
				cronogramaRdo.setDetalleRdo(detalleRdo);
			}

		}

		return rdo;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ec.linde.modulos.dao.AbstractDao#buscarPorId(java.lang.Object)
	 */
	public Rdo buscarPorId(int id) {

		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

		CriteriaQuery<Rdo> cqCabecera = criteriaBuilder.createQuery(Rdo.class);
		Root<Rdo> fromCabecera = cqCabecera.from(Rdo.class);
		Fetch<Object, Object> planOperativo = fromCabecera.fetch("planOperativo", JoinType.LEFT);
		Fetch<Object, Object> proyecto = planOperativo.fetch("proyecto", JoinType.LEFT);

		proyecto.fetch("usuario", JoinType.LEFT);
		proyecto.fetch("persona", JoinType.LEFT);
		proyecto.fetch("cliente", JoinType.LEFT);
		proyecto.fetch("sucursal", JoinType.LEFT);
		proyecto.fetch("contactoCliente", JoinType.LEFT);
		proyecto.fetch("contratista", JoinType.LEFT);
		proyecto.fetch("contactoContratista", JoinType.LEFT);

		Path<Integer> pathId = fromCabecera.get("idRdo");
		cqCabecera.where(criteriaBuilder.equal(pathId, id));
		CriteriaQuery<Rdo> selectRdo = cqCabecera.select(fromCabecera);
		Rdo rdo = em.createQuery(selectRdo).getSingleResult();

		return rdo;
	}

	/**
	 * Carga ProdRdo
	 * 
	 * @param idRdo
	 * @return ProdRdo
	 */
	public Rdo cargarDetalleConMateriales(int idRdo) {

		Rdo rdo = cargarDetalle(idRdo);
		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

		for (DetalleRdo detalleRdo : rdo.getListaDetalleRdo()) {

			// Carga el detalle Concepto Material
			CriteriaQuery<ProdConceptosMateriales> cqConceptoMaterial = criteriaBuilder.createQuery(ProdConceptosMateriales.class);
			Root<ProdConceptosMateriales> fromConceptoMaterial = cqConceptoMaterial.from(ProdConceptosMateriales.class);
			fromConceptoMaterial.fetch("prodMateriales", JoinType.LEFT);
			cqConceptoMaterial.where(criteriaBuilder.equal(fromConceptoMaterial.join("prodConceptos"), detalleRdo.getConcepto()));
			CriteriaQuery<ProdConceptosMateriales> selectConceptoMaterial = cqConceptoMaterial.select(fromConceptoMaterial);

			List<ProdConceptosMateriales> listaConceptoMaterial = em.createQuery(selectConceptoMaterial).getResultList();
			detalleRdo.getConcepto().getProdConceptosMaterialeses().addAll(listaConceptoMaterial);

			for (ProdConceptosMateriales prodConceptosMateriales : listaConceptoMaterial) {
				em.detach(prodConceptosMateriales);
				prodConceptosMateriales.setProdConceptos(detalleRdo.getConcepto());
			}

		}

		return rdo;
	}

}
